﻿using System.Collections.Generic;
using System.Windows;

namespace Game.Map
{
    public struct GameDirection
    {
        public static readonly GameDirection None = 
            new GameDirection(0, 0);
        public static readonly GameDirection North = 
            new GameDirection(0, -1);
        public static readonly GameDirection Northeast = 
            new GameDirection(1, -1);
        public static readonly GameDirection East = 
            new GameDirection(1, 0);
        public static readonly GameDirection Southeast = 
            new GameDirection(1, 1);
        public static readonly GameDirection South = 
            new GameDirection(0, 1);
        public static readonly GameDirection Southwest = 
            new GameDirection(-1, 1);
        public static readonly GameDirection West = 
            new GameDirection(-1, 0);
        public static readonly GameDirection Northwest = 
            new GameDirection(-1, -1);
        
        readonly Point _value;
        
        public GameDirection(double valueX, double valueY)
        {
            _value = new Point(valueX, valueY);
        }
        
        public GameDirection(Point value)
        {
            _value = value;
        }
        
        public Point Value
        {
            get { return _value; }
        }
        
        public static Point Add(Point left, GameDirection right)
        {
            return new Point(
                left.X + right.Value.X, 
                left.Y + right.Value.Y);
        }
        
        public GameDirection Next()
        {
            var array = new[]
            {
                North, Northeast, East, Southeast, 
                South, Southwest, West, Northwest
            };
            var list = new List<GameDirection>(array);
            
            int index = list.IndexOf(this);
            if (index == list.Count)
            {
                index = 0;
            }
            else
            {
                index++;
            }
            
            return array[index];
        }
        
        public static GameDirection FromPoints(Point point1, 
                                               Point point2)
        {
            var dX = point1.X - point2.X;
            var dY = point1.Y - point2.Y;
            
            var delta = new Point(dX, dY);
            return new GameDirection(delta);
        }
        
        #region Equals and GetHashCode implementation
        public override int GetHashCode()
        {
            int hashCode = 0;
            unchecked {
                hashCode += 1000000007 * _value.GetHashCode();
            }
            return hashCode;
        }
        
        public override bool Equals(object obj)
        {
            return (obj is GameDirection) && Equals((GameDirection)obj);
        }

        public bool Equals(GameDirection other)
        {
            return _value == other._value;
        }
        
        public static bool operator ==(GameDirection left, GameDirection right)
        {
            return left.Equals(right);
        }
        
        public static bool operator !=(GameDirection left, GameDirection right)
        {
            return !(left == right);
        }
        #endregion
    
        public override string ToString()
        {
            return "(" + _value.X + "," + _value.Y + ")";
        }
        
    }
}
